package demo04

import (
	"context"
	"fmt"
	"time"
)

// Go中Context的应用场景
// https://juejin.cn/post/7400196065922695204

/*
context的应用场景？
context 包是 Go 语言标准库提供的一个重要工具，用于在多个 Goroutine 之间传递取消信号、超时信息、截止时间以及请求范围的值等。
它在编写并发代码时非常有用，特别是在处理请求的情况下。以下是一些 context 的主要应用场景：

1.取消信号传递：
	当一个 Goroutine 启动了一些子 Goroutine 来执行任务时，可以使用 context 来向这些 Goroutine 发送取消信号，以便在主 Goroutine 接收到取消信号后，
	通知所有子 Goroutine 停止正在执行的任务。这种方式可以有效地控制 Goroutine 的生命周期，避免资源泄漏。
2.超时控制：
	在网络请求或者执行一些 IO 操作时，我们希望能够在一定的时间内完成操作，如果超过了预期的时间，就放弃该操作或者进行一些处理。
	context 可以与 time 包结合使用，设置超时时间，当超时发生时，相关操作可以被取消或者中断。
3.截止时间：
	类似于超时控制，但不同的是，截止时间通常是一个绝对时间点，而不是相对于当前时间的一段时间。例如，某个任务必须在某个特定的截止时间之前完成，否则就没有意义或者需要进行其他处理。
4.请求范围的值传递：
	在一个请求处理流程中，可能需要在多个 Goroutine 中访问同一个请求相关的值（例如请求 ID、用户认证信息等）。
	context 可以用来在 Goroutine 之间传递这些值，而不需要在每个函数中手动传递这些值。
5.控制并发请求：
	在进行并发请求时，可能需要控制同时进行的请求数量，以避免过载服务器或者服务提供商的限制。context 可以在每个请求中进行计数或者限制，并根据情况决定是否进行并发请求。
总之，context 包提供了一种优雅的方式来管理并发代码中的取消、超时、截止时间和值传递等问题，可以帮助开发者编写更加健壮和可靠的并发程序。
*/

// 1. 取消信号传递：
func worker(ctx context.Context) {
	finishDataChan := make(chan struct{})
	go func() {
		// 模拟真实业务场景耗时：sql操作&IO请求操作
		time.Sleep(2 * time.Second)
		finishDataChan <- struct{}{}
	}()
	// 同时监听超时管道&业务请求完成管道，如果3秒到了，则进入取消信号case，说明业务处理超时，该worker进程也会结束，与之对应的业务处理子协程也会结束
	select {
	case <-ctx.Done():
		fmt.Println("worker received cancellation signal.")
	case <-finishDataChan:
		fmt.Println("worker done...")
	}
}

func WorkerDemo() {
	parentCtx, cancel := context.WithCancel(context.Background())
	go worker(parentCtx)

	// Simulate main program execution
	time.Sleep(3 * time.Second)
	// Cancel the context to stop the worker
	cancel()

	// Wait for the worker to finish
	time.Sleep(1 * time.Second)
	fmt.Println("All done...")
}
